/*
 * mvb.c
 *
 *  Created on: 2024年12月12日
 *      Author: Administrator
 */
#include "mvb.h"
#include "user.h"
uint16_t mvb_send_137[16], mvb_send_702[16], mvb_send_706[16];
int i=0;
struct MVB_INFO *pMVBInfo;
struct MVB_INFO mvb_information[128];
unsigned char portIndex[4096];
unsigned short deviceAddr = 0x0069;
unsigned short deviceType = 0x0004;
unsigned short deviceStatus = 0;
unsigned short masterFrameTable[128]  = { 	0x4137,0x4421,0x4021,0x4702,0x4706,0x4703,0x4707,
										0x0000};
unsigned short masterFrameTime[128]  = {    64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
										0x0000};

uint8_t total_mvb_port = 0;
//pFcode数组存放F-CODE及源宿特性（16进制16bit，bit15-bit12为F-CODE，bit11为1表示源端口，bit10为1表示宿端口，注意：bit11与bit10互斥），以0x0000作为结束标志
unsigned short pFcode[128] = {	0x4800,0x4400,0x4400,0x4800,0x4800,0x4400,0x4400,
								0x0000};
//pPort数组存放端口号（16进制），以0x0000作为结束标志
unsigned short pPort[128]  = {	0x0137,0x0421,0x0021,0x0702,0x0706,0x0703,0x0707,
								0x0000};
status_t MvbInit(void)
{
    semc_config_t config;
    semc_sram_config_t sram_config;
    uint32_t clockFrq = EXAMPLE_SEMC_CLK_FREQ;

    /* Initializes the MAC configure structure to zero. */
    memset(&config, 0, sizeof(semc_config_t));
    memset(&sram_config, 0, sizeof(semc_sram_config_t));

    /* Initialize SEMC. */
    SEMC_GetDefaultConfig(&config);
    config.dqsMode = kSEMC_Loopbackdqspad; /* For more accurate timing. */
    SEMC_Init(SEMC, &config);

// config SRAM
    sram_config.cePinMux           = kSEMC_MUXA8;        	// SEMC_ADDR08 is CE0# (IOCR[MUX_A8])
    sram_config.address            = SRAM_BASE;          	// Base address 0x90000000 (BR6[BA])
    sram_config.memsize_kbytes     = 0x10000;				// SRAM0 space size 64MB (BR6[MS])
    sram_config.addrPortWidth      = 8;                    	// Port width (SRAMCR0[COL]) Don't care in SRAM.
    sram_config.advActivePolarity  = kSEMC_AdvActiveLow;   	// ADV# polarity (SRAMCR0[ADVP]) Don't care if not use ADV.
    sram_config.addrMode           = kSEMC_AddrDataNonMux; 	// Non Mux mode (SRAMCR0[AM])
    sram_config.burstLen           = kSEMC_Nor_BurstLen1;	// Burst length (SRAMCR0[BL])
    sram_config.portSize           = kSEMC_PortSize16Bit;	// Port size 16bit (SRAMCR0[PS])
    sram_config.syncMode           = kSEMC_AsyncMode;		// ASYNC mode (SRAMCR0[SYNCEN])
    sram_config.waitEnable         = 0;					// WAIT enable (SRAMCR0[WAITEN])
    sram_config.waitSample         = 0; 					// WAIT sample (SRAMCR0[WAITSP])
    sram_config.advLevelCtrl       = kSEMC_AdvHigh; 		// ADV# level control (SRAMCR0[ADVH]) Don't care if not use ADV.
    sram_config.tCeSetup_Ns        = 20; 					// CE# setup time [nsec] (SRAMCR1[CES]) Need tuning.
    sram_config.tCeHold_Ns         = 20;					// CE# hold time [nsec] (SRAMCR1[CEH]) Need tuning.
    sram_config.tCeInterval_Ns     = 20; 					// CE# interval time [nsec] (SRAMCR2[CEITV]) Need tuning.
    sram_config.readHoldTime_Ns    = 20; 					// Read hold time [nsec] (SRAMCR2[RDH]) Only for SYNC mode.
    sram_config.tAddrSetup_Ns      = 20; 					// ADDR setup time [nsec] (SRAMCR1[AS]) Need tuning.
    sram_config.tAddrHold_Ns       = 20;					// ADDR hold time [nsec] (SRAMCR1[AH]) Need tuning.
    sram_config.tWeLow_Ns          = 200; 					// WE low time [nsec] (SRAMCR1[WEL]) Need tuning.
    sram_config.tWeHigh_Ns         = 125; 					// WE high time [nsec] (SRAMCR1[WEH]) Need tuning.
    sram_config.tReLow_Ns          = 200; 					// RE low time [nsec] (SRAMCR1[REL]) Need tuning.
    sram_config.tReHigh_Ns         = 125;					// RE high time [nsec] (SRAMCR1[REH]) Need tuning.
    sram_config.tTurnAround_Ns     = 20; 					// Turnaround time [nsec] (SRAMCR2[TA]) Need tuning but don't set it to be 0.
    sram_config.tAddr2WriteHold_Ns = 20;					// Address to write data hold time [nsec] (SRAMCR2[AWDH]) Need tuning.
    sram_config.tWriteSetup_Ns     = 20; 					// Write Data setup time [nsec] (SRAMCR2[WDS]) Only for SYNC mode.
    sram_config.tWriteHold_Ns      = 40; 					// Write Data hold time [nsec] (SRAMCR2[WDH]) Only for SYNC mode.
    sram_config.latencyCount       = 20; 					// Latency count [nsec] (SRAMCR2[LC]) Only for SYNC mode.
    sram_config.readCycle          = 20; 					// read time [nsec] (SRAMCR2[RD]) Only for SYNC mode.
    sram_config.delayChain         = 20; 					// typically not used in SRAM. (DCCR [SRAMXVAL], DCCR [SRAMXEN], DCCR [SRAM0VAL], DCCR [SRAM0EN])

    return SEMC_ConfigureSRAM(SEMC, &sram_config, clockFrq);
}

// With workaround for WAIT enabled.
//With SRAM timeout countermeasure (Unmodified EVK has no SRAM device, so WAIT signal is not input and timeout occurs)
//SEMC does not transfer/receive data when wait pin is asserted
void test_sram(void)
{
	unsigned short * p0;
    p0 = (unsigned short *)0x91000000;
    char * p1;
    p1 = (char *)0x92000000;


//  1st write.
//   	GPIO_PinWrite(BOARD_INITPINS_WAIT_CTRL_PERIPHERAL, BOARD_INITPINS_WAIT_CTRL_CHANNEL, 1); // WAIT_CTRL Hi
    p0[0] = i;
//    for(int i=0; i <1000*1000; i++);	// Workaround for WAIT enabled without actual SRAM device.
    SEMC->INTR |= 0x3F;				// Write 1 to Clear
    SEMC->MCR  |= 0x1;				// Reset all internal logic in the SEMC except configuration registers.
    asm(" dsb");					// No instruction in program order after this instruction executes until this instruction completes. This instruction completes when:
    								//-All explicit memory accesses before this instruction complete.
    								//-All Cache, Branch predictor and TLB maintenance operations before this instruction complete.
    while(SEMC->MCR & 1)			//    :
        ;							//    :
//   	GPIO_PinWrite(BOARD_INITPINS_WAIT_CTRL_PERIPHERAL, BOARD_INITPINS_WAIT_CTRL_CHANNEL, 0); 	// WAIT_CTRL Low (Initial)

// 2nd write.
 //  	GPIO_PinWrite(BOARD_INITPINS_WAIT_CTRL_PERIPHERAL, BOARD_INITPINS_WAIT_CTRL_CHANNEL, 1); // WAIT_CTRL Hi
    p0[1] = 1;
    SEMC->INTR |= 0x3F;				// Write 1 to Clear
    SEMC->MCR  |= 0x1;				// Reset all internal logic in the SEMC except configuration registers.
    asm(" dsb");					// No instruction in program order after this instruction executes until this instruction completes. This instruction completes when:
    								//-All explicit memory accesses before this instruction complete.
    								//-All Cache, Branch predictor and TLB maintenance operations before this instruction complete.
    while(SEMC->MCR & 1)			//    :
        ;
//   	GPIO_PinWrite(BOARD_INITPINS_WAIT_CTRL_PERIPHERAL, BOARD_INITPINS_WAIT_CTRL_CHANNEL, 0); 	// WAIT_CTRL Low (Initial)

#if 0
//   	GPIO_PinWrite(BOARD_INITPINS_WAIT_CTRL_PERIPHERAL, BOARD_INITPINS_WAIT_CTRL_CHANNEL, 1); // WAIT_CTRL Hi
    p1[0] = 0;
    SEMC->INTR |= 0x3F;				// Write 1 to Clear
    SEMC->MCR  |= 0x1;				// Reset all internal logic in the SEMC except configuration registers.
    asm(" dsb");					// No instruction in program order after this instruction executes until this instruction completes. This instruction completes when:
    								//-All explicit memory accesses before this instruction complete.
    								//-All Cache, Branch predictor and TLB maintenance operations before this instruction complete.
    while(SEMC->MCR & 1)			//    :
        ;
//   	GPIO_PinWrite(BOARD_INITPINS_WAIT_CTRL_PERIPHERAL, BOARD_INITPINS_WAIT_CTRL_CHANNEL, 0); 	// WAIT_CTRL Low (Initial)


 //  	GPIO_PinWrite(BOARD_INITPINS_WAIT_CTRL_PERIPHERAL, BOARD_INITPINS_WAIT_CTRL_CHANNEL, 1); // WAIT_CTRL Hi
    p1[1] = 1;
    SEMC->INTR |= 0x3F;				// Write 1 to Clear
    SEMC->MCR  |= 0x1;				// Reset all internal logic in the SEMC except configuration registers.
    asm(" dsb");					// No instruction in program order after this instruction executes until this instruction completes. This instruction completes when:
    								//-All explicit memory accesses before this instruction complete.
    								//-All Cache, Branch predictor and TLB maintenance operations before this instruction complete.
    while(SEMC->MCR & 1)			//    :
        ;
//   	GPIO_PinWrite(BOARD_INITPINS_WAIT_CTRL_PERIPHERAL, BOARD_INITPINS_WAIT_CTRL_CHANNEL, 0); 	// WAIT_CTRL Low (Initial)
#endif
}

void writeConfig(void)
{
	unsigned short i=0;
	unsigned short PI=0x0008;

	*(__IO uint16_t *)(PI_BASE_ADDR+0x8000) = 0xF00F;
    SEMC->INTR |= 0x3F;				// Write 1 to Clear
    SEMC->MCR  |= 0x1;				// Reset all internal logic in the SEMC except configuration registers.
    asm(" dsb");					// No instruction in program order after this instruction executes until this instruction completes. This instruction completes when:
    								//-All explicit memory accesses before this instruction complete.
    								//-All Cache, Branch predictor and TLB maintenance operations before this instruction complete.
    while(SEMC->MCR & 1)			//    :
        ;

	for(i = 0; i< 0x1000; i++)
	{
		*(__IO uint16_t *)(PI_BASE_ADDR+(i<<1)) = 0x0000;
	    SEMC->INTR |= 0x3F;
	    SEMC->MCR  |= 0x1;
	    asm(" dsb");
	    while(SEMC->MCR & 1);
	}

	for(i = 0; pPort[i] != 0x0000; i++)
	{
		total_mvb_port++;
		*(__IO uint16_t *)(PI_BASE_ADDR+(pPort[i]<<1)) = PI;
	    SEMC->INTR |= 0x3F;
	    SEMC->MCR  |= 0x1;
	    asm(" dsb");
	    while(SEMC->MCR & 1)
	    	;
		*(__IO uint16_t *)(PCS_BASE_ADDR + 0x00 + (PI<<3)) = pFcode[i];
	    SEMC->INTR |= 0x3F;
	    SEMC->MCR  |= 0x1;
	    asm(" dsb");
	    while(SEMC->MCR & 1)
	    	;
		*(__IO uint16_t *)(PCS_BASE_ADDR + 0x02 + (PI<<3)) = 0;
	    SEMC->INTR |= 0x3F;
	    SEMC->MCR  |= 0x1;
	    asm(" dsb");
	    while(SEMC->MCR & 1)
	    	;
		*(__IO uint16_t *)(PCS_BASE_ADDR + 0x04 + (PI<<3)) = 0xFFFF;
	    SEMC->INTR |= 0x3F;
	    SEMC->MCR  |= 0x1;
	    asm(" dsb");
	    while(SEMC->MCR & 1)
	    	;
		*(__IO uint16_t *)(PCS_BASE_ADDR + 0x06 + (PI<<3)) = 0;
	    SEMC->INTR |= 0x3F;
	    SEMC->MCR  |= 0x1;
	    asm(" dsb");
	    while(SEMC->MCR & 1)
	    	;

		mvb_information[i].pPort = pPort[i];
		mvb_information[i].pFcode = pFcode[i];
		mvb_information[i].VP = 0x0000;
		mvb_information[i].PI = PI;
		mvb_information[i].PCS0 = PCS_BASE_ADDR + 0x00 + (PI<<3);
		mvb_information[i].PCS1 = PCS_BASE_ADDR + 0x02 + (PI<<3);
		mvb_information[i].PCS2 = PCS_BASE_ADDR + 0x04 + (PI<<3);
		mvb_information[i].PCS3 = PCS_BASE_ADDR + 0x06 + (PI<<3);
		mvb_information[i].DataBaseAddr = DATA_BASE_ADDR+(PI<<3);
		mvb_information[i].p_data_bytes = (uint8_t *)mvb_information[i].data;
		PI = PI + 8;
		portIndex[pPort[i]] = i;
	}

//	*(__IO uint16_t *)(DEVICE_BASE_ADDR) = deviceAddr;
//	*(__IO uint16_t *)(DEVICE_STATUS_ADDR) = (deviceType<<12);

	*(__IO uint16_t *)(PI_BASE_ADDR+0x8000) = 0xF000;
    SEMC->INTR |= 0x3F;
    SEMC->MCR  |= 0x1;
    asm(" dsb");
    while(SEMC->MCR & 1)
    	;

//	return 0;
}

int writeMasterFrameTable(void)
{
	unsigned short i=0;

	*(__IO uint16_t *)(PI_BASE_ADDR+0x8000) = 0xF55F;
    SEMC->INTR |= 0x3F;
    SEMC->MCR  |= 0x1;
    asm(" dsb");
    while(SEMC->MCR & 1)
    	;

	for(i = 0; i< 128; i++)
	{
		*(__IO uint16_t *)(MASTER_FRAME_TABLE_BASE_ADDR+(i<<1)) = deviceAddr|0xF000;
	    SEMC->INTR |= 0x3F;
	    SEMC->MCR  |= 0x1;
	    asm(" dsb");
	    while(SEMC->MCR & 1)
	    	;
		*(__IO uint16_t *)(MASTER_FRAME_TIME_BASE_ADDR+(i<<1)) = 0x0000;
	    SEMC->INTR |= 0x3F;
	    SEMC->MCR  |= 0x1;
	    asm(" dsb");
	    while(SEMC->MCR & 1)
	    	;
	}

	for(i = 0; masterFrameTable[i] != 0x0000; i++)
	{
		*(__IO uint16_t *)(MASTER_FRAME_TABLE_BASE_ADDR+(i<<1)) = masterFrameTable[i];
	    SEMC->INTR |= 0x3F;
	    SEMC->MCR  |= 0x1;
	    asm(" dsb");
	    while(SEMC->MCR & 1)
	    	;
		*(__IO uint16_t *)(MASTER_FRAME_TIME_BASE_ADDR+(i<<1)) = masterFrameTime[i];
	    SEMC->INTR |= 0x3F;
	    SEMC->MCR  |= 0x1;
	    asm(" dsb");
	    while(SEMC->MCR & 1)
	    	;
	}

	*(__IO uint16_t *)(PI_BASE_ADDR+0x8000) = 0xF550;
    SEMC->INTR |= 0x3F;
    SEMC->MCR  |= 0x1;
    asm(" dsb");
    while(SEMC->MCR & 1)
    	;

	return 0;
}
void MvbSend()
{
	uint32_t i=0;
	uint32_t j=0;
	uint16_t pi = 0;
	for(i=0;i<total_mvb_port;i++)
	{
		pi = *(__IO uint16_t *)(PI_BASE_ADDR+(mvb_information[i].pPort<<1));//read PI
		if(pi == mvb_information[i].PI)
		{
			if(mvb_information[i].pFcode&0x0800)//Source Port
			{
				*(__IO uint16_t *)(mvb_information[i].PCS1) = mvb_information[i].VP^0x0040;//write VP

				for(j=0;j<((1<<(mvb_information[i].pFcode>>12)));j++)
				{
					mvb_information[0].data[j] = mvb_send_137[j];
					mvb_information[3].data[j] = mvb_send_702[j];
					mvb_information[4].data[j] = mvb_send_706[j];
					*(__IO uint16_t *)(mvb_information[i].DataBaseAddr+(mvb_information[i].VP<<7)+(j<<1)) = mvb_information[i].data[j];
				}

				mvb_information[i].VP = mvb_information[i].VP^0x0040;
			}
		}
		else
		{
//			printf("error send PI\n");
		}
	}
}
void MvbRecv()
{
	uint32_t i=0;
	uint32_t j=0;
	uint16_t pi = 0;
	for(i=0;i<total_mvb_port;i++)
	{
		pi = *(__IO uint16_t *)(PI_BASE_ADDR+(mvb_information[i].pPort<<1));//read PI
		if(pi == mvb_information[i].PI)
		{
			if(mvb_information[i].pFcode&0x0400)//Sink Port
			{
				mvb_information[i].VP = *(__IO uint16_t *)(mvb_information[i].PCS1);
				for(j=0;j<((1<<(mvb_information[i].pFcode>>12)));j++)
				{
					mvb_information[i].data[j] = *(__IO uint16_t *)(mvb_information[i].DataBaseAddr+(mvb_information[i].VP<<7)+(j<<1));
				}
//					mvb_information[i].frameLife = *(__IO uint16_t *)(mvb_information[i].PCS2);
//					mvb_information[i].globalLife = *(__IO uint16_t *)(LIFE_BASE_ADDR);
//					printf("frameLife: %d globalLife: %d data: 0x%x\n",mvb_information[0].frameLife,mvb_information[0].globalLife,mvb_information[0].data[0]);
				for(uint16_t m=0;m<16;m++)
				{
					M_MVB421[m] = mvb_information[1].data[m];
					M_MVB021[m] = mvb_information[2].data[m];

					M_MVB703[m] = mvb_information[5].data[m];
					M_MVB707[m] = mvb_information[6].data[m];
				}
			}
		}
		else
		{
			//printf("error rec PI\n");
		}
	}

}
